package server

import (
	"context"
	"fmt"
	"p2p-server/pkg/util"
	"sync"
	"time"

	"github.com/chuckpreslar/emission"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
)

// WebSocketConfig WebSocket配置结构
type WebSocketConfig struct {
	PingPeriod           time.Duration `json:"ping_period"`
	MaxReconnectAttempts int           `json:"max_reconnect_attempts"`
	ReconnectDelay       time.Duration `json:"reconnect_delay"`
	MaxQueueSize         int           `json:"max_queue_size"`
}

// getWebSocketConfig 获取WebSocket配置
func getWebSocketConfig() *WebSocketConfig {
	config := &WebSocketConfig{
		PingPeriod:           5 * time.Second,
		MaxReconnectAttempts: 5,
		ReconnectDelay:       2 * time.Second,
		MaxQueueSize:         1000,
	}
	
	// 从配置文件读取
	if pingPeriod := g.Cfg().MustGet(context.Background(), "websocket.ping_period").Duration(); pingPeriod > 0 {
		config.PingPeriod = pingPeriod
	}
	if maxAttempts := g.Cfg().MustGet(context.Background(), "websocket.max_reconnect_attempts").Int(); maxAttempts > 0 {
		config.MaxReconnectAttempts = maxAttempts
	}
	if reconnectDelay := g.Cfg().MustGet(context.Background(), "websocket.reconnect_delay").Duration(); reconnectDelay > 0 {
		config.ReconnectDelay = reconnectDelay
	}
	if maxQueueSize := g.Cfg().MustGet(context.Background(), "websocket.max_queue_size").Int(); maxQueueSize > 0 {
		config.MaxQueueSize = maxQueueSize
	}
	
	return config
}

// MessageItem 消息队列项
type MessageItem struct {
	Data      string
	Timestamp time.Time
	Retries   int
}

// ConnectionState 连接状态
type ConnectionState int

const (
	StateDisconnected ConnectionState = iota
	StateConnecting
	StateConnected
	StateReconnecting
)

type WebSocketConn struct {
	*emission.Emitter

	socket *ghttp.WebSocket
	mutex  *sync.RWMutex
	closed bool

	// 配置
	config *WebSocketConfig

	// 重连相关
	url             string
	reconnectCount  int
	state          ConnectionState
	stateMutex     *sync.RWMutex

	// 消息队列相关
	messageQueue    chan *MessageItem
	queueMutex     *sync.Mutex
	ctx            context.Context
	cancel         context.CancelFunc

	// 心跳相关
	lastPong       time.Time
	pongMutex      *sync.RWMutex
}

func NewWebSocketConn(socket *ghttp.WebSocket) *WebSocketConn {
	return NewWebSocketConnWithURL(socket, "")
}

// NewWebSocketConnWithURL 创建带URL的WebSocket连接（支持重连）
func NewWebSocketConnWithURL(socket *ghttp.WebSocket, url string) *WebSocketConn {
	ctx, cancel := context.WithCancel(context.Background())
	config := getWebSocketConfig()
	
	conn := &WebSocketConn{
		Emitter:        emission.NewEmitter(),
		socket:         socket,
		mutex:          &sync.RWMutex{},
		closed:         false,
		config:         config,
		url:            url,
		reconnectCount: 0,
		state:          StateConnected,
		stateMutex:     &sync.RWMutex{},
		messageQueue:   make(chan *MessageItem, config.MaxQueueSize),
		queueMutex:     &sync.Mutex{},
		ctx:            ctx,
		cancel:         cancel,
		lastPong:       time.Now(),
		pongMutex:      &sync.RWMutex{},
	}
	
	// 启动消息队列处理器
	go conn.processMessageQueue()
	
	return conn
}

// processMessageQueue 处理消息队列
func (conn *WebSocketConn) processMessageQueue() {
	for {
		select {
		case <-conn.ctx.Done():
			return
		case item := <-conn.messageQueue:
			if conn.GetState() == StateConnected {
				err := conn.sendDirectly(item.Data)
				if err != nil {
					util.Warnf("发送消息失败: %v", err)
					// 重试逻辑
					if item.Retries < 3 {
						item.Retries++
						select {
						case conn.messageQueue <- item:
						default:
							util.Warnf("消息队列已满，丢弃消息")
						}
					}
				}
			} else {
				// 连接断开时，将消息重新放回队列
				select {
				case conn.messageQueue <- item:
				default:
					util.Warnf("消息队列已满，丢弃消息")
				}
				time.Sleep(100 * time.Millisecond) // 等待重连
			}
		}
	}
}

// GetState 获取连接状态
func (conn *WebSocketConn) GetState() ConnectionState {
	conn.stateMutex.RLock()
	defer conn.stateMutex.RUnlock()
	return conn.state
}

// SetState 设置连接状态
func (conn *WebSocketConn) SetState(state ConnectionState) {
	conn.stateMutex.Lock()
	defer conn.stateMutex.Unlock()
	conn.state = state
}

func (conn *WebSocketConn) ReadMessage() {
	in := make(chan []byte)
	stop := make(chan struct{})
	pingTicker := time.NewTicker(conn.config.PingPeriod)

	var c = conn.socket

	go func() {
		for {
			_, message, err := c.ReadMessage()

			if err != nil {
				util.Warnf("获取错误:%v", err)
				conn.SetState(StateDisconnected)
				conn.Emit("close", 1000, err.Error())
				// 尝试重连
				if conn.url != "" {
					go conn.attemptReconnect()
				}
				close(stop)
				break
			}
			
			// 更新最后收到pong的时间
			conn.updateLastPong()
			in <- message
		}
	}()

	for {
		select {
		case _ = <-pingTicker.C:
			util.Infof("发送心跳包....")

			heartPackage := map[string]interface{}{
				"type": "heartPackage",
				"data": "",
			}
			if err := conn.Send(util.Marshal(heartPackage)); err != nil {
				util.Infof("发送心跳包错误....")
				pingTicker.Stop()
				return
			}
			
			// 检查心跳超时
			if conn.isHeartbeatTimeout() {
				util.Warnf("心跳超时，关闭连接")
				conn.Close()
				return
			}
			
		case message := <-in:
			{
				util.Infof("接收到的数据: %s", message)
				conn.Emit("message", []byte(message))
			}
		case <-stop:
			return
		case <-conn.ctx.Done():
			pingTicker.Stop()
			return
		}
	}
}

// SendQueued 将消息加入队列发送
func (conn *WebSocketConn) SendQueued(message string) error {
	if conn.closed {
		return fmt.Errorf("websocket: connection closed")
	}
	
	item := &MessageItem{
		Data:      message,
		Timestamp: time.Now(),
		Retries:   0,
	}
	
	select {
	case conn.messageQueue <- item:
		return nil
	default:
		return fmt.Errorf("message queue is full")
	}
}

// Send 直接发送消息（保持向后兼容）
func (conn *WebSocketConn) Send(message string) error {
	if conn.GetState() == StateConnected {
		return conn.sendDirectly(message)
	}
	// 连接断开时使用队列
	return conn.SendQueued(message)
}

// sendDirectly 直接发送消息到WebSocket
func (conn *WebSocketConn) sendDirectly(message string) error {
	util.Infof("发送数据:%s", message)
	conn.mutex.Lock()
	defer conn.mutex.Unlock()
	if conn.closed {
		return fmt.Errorf("websocket: write closed")
	}
	return conn.socket.WriteMessage(ghttp.WsMsgText, []byte(message))
}

// attemptReconnect 尝试重连
func (conn *WebSocketConn) attemptReconnect() {
	if conn.url == "" {
		return
	}
	
	conn.SetState(StateReconnecting)
	
	for conn.reconnectCount < conn.config.MaxReconnectAttempts {
		conn.reconnectCount++
		util.Infof("尝试重连 %d/%d", conn.reconnectCount, conn.config.MaxReconnectAttempts)
		
		time.Sleep(conn.config.ReconnectDelay)
		
		// 这里需要根据实际情况实现重连逻辑
		// 由于ghttp.WebSocket没有直接的重连方法，这里只是示例
		util.Infof("重连逻辑需要在上层实现")
		conn.Emit("reconnect_attempt", conn.reconnectCount)
		
		// 模拟重连成功的情况
		// 实际应用中需要重新建立WebSocket连接
		break
	}
	
	if conn.reconnectCount >= conn.config.MaxReconnectAttempts {
		util.Warnf("重连失败，已达到最大重连次数")
		conn.SetState(StateDisconnected)
		conn.Emit("reconnect_failed")
	} else {
		conn.SetState(StateConnected)
		conn.reconnectCount = 0
		conn.Emit("reconnected")
	}
}

// updateLastPong 更新最后收到pong的时间
func (conn *WebSocketConn) updateLastPong() {
	conn.pongMutex.Lock()
	defer conn.pongMutex.Unlock()
	conn.lastPong = time.Now()
}

// isHeartbeatTimeout 检查心跳是否超时
func (conn *WebSocketConn) isHeartbeatTimeout() bool {
	conn.pongMutex.RLock()
	defer conn.pongMutex.RUnlock()
	return time.Since(conn.lastPong) > conn.config.PingPeriod*3 // 3个心跳周期超时
}

func (conn *WebSocketConn) Close() {
	conn.mutex.Lock()
	defer conn.mutex.Unlock()
	if conn.closed == false {
		util.Infof("关闭WebSocket连接:", conn)
		
		// 设置状态为断开
		conn.SetState(StateDisconnected)
		
		// 取消context，停止所有goroutine
		if conn.cancel != nil {
			conn.cancel()
		}
		
		// 关闭WebSocket连接
		if conn.socket != nil {
			conn.socket.Close()
		}
		
		// 关闭消息队列
		close(conn.messageQueue)
		
		conn.closed = true
		conn.Emit("close", 1000, "normal closure")
	} else {
		util.Infof("连接已关闭:", conn)
	}
}

// GetQueueSize 获取消息队列大小
func (conn *WebSocketConn) GetQueueSize() int {
	return len(conn.messageQueue)
}

// ClearQueue 清空消息队列
func (conn *WebSocketConn) ClearQueue() {
	conn.queueMutex.Lock()
	defer conn.queueMutex.Unlock()
	
	// 清空队列中的所有消息
	for len(conn.messageQueue) > 0 {
		select {
		case <-conn.messageQueue:
		default:
			return
		}
	}
}

// IsConnected 检查连接是否正常
func (conn *WebSocketConn) IsConnected() bool {
	return conn.GetState() == StateConnected && !conn.closed
}

// GetReconnectCount 获取重连次数
func (conn *WebSocketConn) GetReconnectCount() int {
	return conn.reconnectCount
}
